#include "discobase.h"
#include "protocol.h"
#include "article.h"
#include <iostream>
#include <fstream>
#include <sys/stat.h>
#include <sys/types.h>
#include <stdlib.h>
#include <dirent.h>
#include <sstream>
#include <algorithm>


using namespace std;
namespace client_server {

	void replace_all(string& s, const string& from, const string& to){	
		size_t index = s.find(from);
		while(index != string::npos) {
			s.erase(index, from.size());
			s.insert(index, to);
			index = s.find(from, index + to.size());
		}
	}
	/* Create/setups the DiscoBase */
	DiscoBase::DiscoBase(){
		//läs in indexfil om den finns, annars skapa
		ifstream file("index",ios::in);
		maxIndex = 0;
		if(!file){
			file.clear();
			file.close();
			ofstream ofile("index",ios::out);
			ofile.close();
			file.open("index", ios::in);
		}
		if(file){
			while(!file.eof()){
				int id;
				string name;
				file >> id;
				file >> name;
				if(name.size() != 0) {
					newsgroups.push_back(make_pair(id, name));
					if(maxIndex < id)
						maxIndex = id;
				}
				
			}
		}
	}
		
	/* Kills the DiscoBase */
	DiscoBase::~DiscoBase(){
		
	}
		
	/* Creates a new newsgroup. Throws exception if newsgroup already exists */
	void DiscoBase::create_newsgroup(std::string name) throw(DatabaseException){
		vector<pair<int, string> >::const_iterator itr = newsgroups.begin();
		while(itr != newsgroups.end()){
			if(itr->second.compare(name) == 0) {
				DatabaseException dbe;
				dbe.id = protocol::Protocol::ERR_NG_ALREADY_EXISTS;
				throw dbe;
			}
			++itr;
		}
		newsgroups.push_back(make_pair(++maxIndex,name));
		ofstream file("index", ios::app);
		if(file){
			file << maxIndex << " " << name << endl;
		}
		mkdir(("newsgroups/"+name).c_str(),0777);
	}
		
	/* Deletes a newsgroup. Throws exception if newsgroup does not exist */
	void DiscoBase::delete_newsgroup(int group_id) throw(DatabaseException){
		vector<pair<int, string> >::iterator itr = newsgroups.begin();
		bool removed = false;
		while(itr != newsgroups.end()){
			if(itr->first == group_id) {
				removed = true;
				string dir = "newsgroups/" + itr->second;
				replace_all(dir, " ", "\\ ");
				system(("rm -rf " + dir).c_str());
				newsgroups.erase(itr);
				vector<pair<int, string> >::const_iterator itr2 = newsgroups.begin();
				ofstream file("index", ios::trunc);
				if(file){
					while(itr2 != newsgroups.end()){
						file << itr2->first << " " << itr2->second << endl;
						++itr2;
					}
				}
				break;
			}
			++itr;
		}
		if(!removed){
			DatabaseException dbe;
			dbe.id = protocol::Protocol::ERR_NG_ALREADY_EXISTS;
			throw dbe;
		}
	}
		
	/* Returns a vector with pairs of all newsgroupId + newsgroup name. */
	std::vector<std::pair<int, string> > DiscoBase::list_newsgroups(){
		return newsgroups;
	}		
		
	/* Creates a new article. Throws exception if newsgroup does not exist. */
	void DiscoBase::create_article(int group_id, std::string name, std::string author, std::string content) throw(DatabaseException){
		vector<pair<int, string> >::iterator itr = newsgroups.begin();
		bool found = false;
		while(itr != newsgroups.end()){
			if(itr->first == group_id) {
				found = true;
				DIR* dirp = opendir(("newsgroups/"+itr->second).c_str());
				dirent* dp = readdir(dirp);
				int maxName = 0;
				while (dp != 0) {
					const char* filename = dp->d_name;
					if(atoi(filename) > maxName){
						maxName = atoi(filename);
					}
					dp = readdir(dirp);
				}
				closedir(dirp);
				ostringstream ss;
				ss << "newsgroups/" << itr->second << "/";
				ss << ++maxName;
				ss << ".awesome";
				cout << ss.str() << endl;
				ofstream file(ss.str().c_str(), ios::out);
				if(file){
					file << name << endl;
					file << author << endl;
					file << content << endl;
				}
				break;
			}
			++itr;
		}
		if(!found){
			DatabaseException dbe;
			dbe.id = protocol::Protocol::ERR_NG_DOES_NOT_EXIST;
			throw dbe;
		}
	}
    		
    	/* Deletes an article. Throws exception if newsgroup or article does not exist. */
	void DiscoBase::delete_article(int group_id, int art_id) throw(DatabaseException){
		vector<pair<int, string> >::iterator itr = newsgroups.begin();
		bool found = false;
		while(itr != newsgroups.end()){
			if(itr->first == group_id) {
				found = true;
				DIR* dirp = opendir(("newsgroups/"+itr->second).c_str());
				dirent* dp = readdir(dirp);
				bool file_found = false;
				while (dp != 0) {
					string filename = dp->d_name;
					string extension = (filename.length() > 8) ? filename.substr(filename.length() - 8, 8) : "";
					if (extension == ".awesome") {
						if(atoi(filename.substr(0, filename.length() - 8).c_str()) == art_id){
							file_found = true;
							ostringstream ss;
							ss << "newsgroups/" << itr->second << "/";
							ss << art_id;
							ss << ".awesome";
							string dir = ss.str();
							replace_all(dir, " ", "\\ ");
							system(("rm " + dir).c_str());
						}
					}
					dp = readdir(dirp);
				}
				closedir(dirp);
				if(!file_found){
					DatabaseException dbe;
					dbe.id = protocol::Protocol::ERR_ART_DOES_NOT_EXIST;
					throw dbe;
				}
				break;
			}
			++itr;
		}
		if(!found){
			DatabaseException dbe;
			dbe.id = protocol::Protocol::ERR_NG_DOES_NOT_EXIST;
			throw dbe;
		}
	
	}
	
	struct note  {
		bool operator()(pair<int, string> p1, pair<int, string> p2) {
			return p1.first < p2.first;
		}
	}comp;
		
	/* Returns a vector with pairs of all articleId + article name or empty vector if no articles exists in the newsgroup. */
	vector<pair<int, string> > DiscoBase::list_articles(int group_id) throw(DatabaseException){
		vector<pair<int, string> >::iterator itr = newsgroups.begin();
		vector<pair<int, string> > NAMES;
		bool found = false;
		while(itr != newsgroups.end()){
			if(itr->first == group_id) {
				found = true;
				DIR* dirp = opendir(("newsgroups/"+itr->second).c_str());
				dirent* dp = readdir(dirp);
				while (dp != 0) {
					string filename = dp->d_name;
					string extension = (filename.length() > 8) ? filename.substr(filename.length() - 8, 8) : "";
					if (extension == ".awesome") {
						ifstream file(("newsgroups/"+itr->second+"/"+filename).c_str(), ios::in);
						if(file){
							string name;
							getline(file, name);	
							NAMES.push_back(make_pair(atoi(filename.substr(0, filename.length() -8).c_str()), name));	
						}
					}
					dp = readdir(dirp);
				}
				closedir(dirp);
				break;
			}
			++itr;
		}
		if(!found){
			DatabaseException dbe;
			dbe.id = protocol::Protocol::ERR_NG_DOES_NOT_EXIST;
			throw dbe;
		}
		sort(NAMES.begin(), NAMES.end(), comp);
		return NAMES;
	}
	

		
	/* Returns an article object with the requested article. Throws exception if newsgroup or article does not exist. */
	Article DiscoBase::get_article(int group_id, int art_id) throw(DatabaseException){
		vector<pair<int, string> >::iterator itr = newsgroups.begin();
		while(itr != newsgroups.end()){
			if(itr->first == group_id) {
				ostringstream ss;
				ss << "newsgroups/" << itr->second << "/";
				ss << art_id;
				ss << ".awesome";
				ifstream file(ss.str().c_str());
				if(file){
					string name, author, content, temp;
					getline(file,name);
					getline(file,author);
					bool first_line = true;
					while(!getline(file, temp).eof()){
						if(first_line) {
							first_line = false;
						} else {
							content += '\n';
						}
						content += temp;
					}
					return Article(name, author, content);
				} else {
					DatabaseException dbe;
					dbe.id = protocol::Protocol::ERR_ART_DOES_NOT_EXIST;
					throw dbe;
				}
					
			}
			++itr;
		}
		DatabaseException dbe;
		dbe.id = protocol::Protocol::ERR_NG_DOES_NOT_EXIST;
		throw dbe;
	}
	
			

}
